home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume2 / util / dresdocs < prev    next >
Internet Message Format  |  1988-10-25  |  59KB

  1. Path: xanth!nic.MR.NET!hal!cwjcc!tut.cis.ohio-state.edu!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v02i015:  dres - an object-oriented resource library (docs)
  5. Message-ID: <9820@swan.ulowell.edu>
  6. Date: 25 Oct 88 00:08:17 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 1588
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: dillon@cory.berkeley.edu (Matt Dillon)
  12. Posting-number: Volume 2, Issue 15
  13. Archive-name: util/dres.docs
  14.  
  15. # This is a shell archive.  Remove anything before this line
  16. # then unpack it by saving it in a file and typing "sh file"
  17. # (Files unpacked will be owned by you and have default permissions).
  18. # This archive contains the following files:
  19. #    ipc.doc
  20. #    lists.doc
  21. #    memory.doc
  22. #    misc.doc
  23. #    qints.doc
  24. #    res.doc
  25. #    runlib.doc
  26. #    timedate.doc
  27. #
  28. if `test ! -s ipc.doc`
  29. then
  30. echo "writing ipc.doc"
  31. cat > ipc.doc << '\Rogue\Monster\'
  32.  
  33.             IPC.DOC  (DRES.LIBRARY)
  34.  
  35.                 Matthew Dillon
  36.               25 September 1988
  37.  
  38.  
  39.     Special note.  I've tried my best, but this document is somewhat
  40.     lacking in the exact mechanics and implementation of IPC.  Please
  41.     refer to the source module to resolve such questions.
  42.  
  43.     The IPC section of the DRES.LIBRARY pertains to the sending of commands
  44. and retrieval of results between arbitrary processes without conflict.
  45. Processes which use IPC come in three flavors:
  46.  
  47.     (1) A process which is able to accept and process IPC commands
  48.     (2) A process which might send IPC commands to other processes
  49.     (3) A process which does both.
  50.  
  51.     The IPC mechanism implemented by this library is inherently asychronous
  52. in nature (messages and ports), but also provides a synchronous call
  53. specially tailored for cases (2) and (3).  Doing IPC commands synchronously
  54. has certain advantages, the greatest of which is that the implementation by
  55. application software is greatly simplified.  The synchronous call gets
  56. around possible deadlocks in case (3) by interrupting itself and calling a
  57. handler if incomming messages occur while it is waiting for the sent
  58. message to complete.
  59.  
  60.     The greatest feature of this IPC mechanism is a great flexibility in
  61. who allocates and deallocates the message buffers.  Both the source and
  62. destination processes have a wide range of options concerning message
  63. buffers.  Unless otherwise specified, an allocated copy of the message
  64. buffer is automatically made and used which allows the send or reply message
  65. buffer used by the process to be immediately discarded.  Additionaly, a
  66. destination IPCPort can be flagged to force incomming messages to be
  67. allocated no matter what the sender requests.
  68.  
  69.     NOTE:   The term 'allocation of messages' inherently means that if the
  70. message is allocated, the user of the message can munge it however he likes
  71. (exception: IF_GLOBAL messages that are propogated through all IPC ports).
  72. Allocated messages are automatically FreeMem()d by the IPC subsystem or
  73. by the receiver.   Also, WHEN DUPLICATION OF MESSAGES OCCUR, THE ALLOCATED
  74. MEMORY IS OF THE SAME TYPE AS THE ORIGINAL BUFFER.
  75.  
  76.     NOTE:   Do not get confused by the many different ways messages buffers
  77. can be allocated.  A message buffer will never be allocated-duplicate more
  78. than once.  For example, if the source specifies that it is passing an
  79. allocated buffer, the further duplication is done by the IPC subsystem.
  80.  
  81.     -The sender can allocate the message buffer himself and pass that,
  82.      pass a temporary buffer which the IPC subsystem duplicates, or pass
  83.      a static buffer to the destination without the overhead of allocation
  84.      and duplication.
  85.  
  86.     -The receiver of a particular message can determine whether that message
  87.      was allocated and FreeMem() it himself, can allow the IPC subsystem
  88.      to free allocated messages, and can even force all incomming messages
  89.      on his IPC port to be allocated no matter what the sender specifies.
  90.      Forcing the IPC subsystem to allocate otherwise static messages is
  91.      a very useful ability to have.  For instance, the parser employed by
  92.      the receiver of a message might destroy or modify the message buffer
  93.      during parser, while the original sender of the message might have
  94.      used a static string or otherwise expected the buffer not to be
  95.      screwed up.  By the receiver being able to specify that he WANTS the
  96.      buffer to be an allocated duplicate because he intends to modify it
  97.      without permission is a good thing.  Even though the sender passes
  98.      a static buffer to the IPC subsystem, that subsystem will allocate
  99.      and duplicate it for the receiver.
  100.  
  101.     -In his reply to the sender, the receiver has the same sort of control
  102.      as sender in terms of how the reply message buffer is allocated.  After
  103.      getting the reply back, the original sender can determine whether the
  104.      reply buffer was allocated and FreeMem() it himself, or allow the IPC
  105.      subsystem to free it when he is through with the reply.
  106.  
  107.     -Finally, the receiver of the original message can even free his own
  108.      reply buffer when the original sender is through with it!
  109.  
  110.     So in general, one can use either the IPC subsystem's automatic buffer
  111. copying feature (the default), use no buffer copying at all, or use one's
  112. own scheme.
  113.  
  114.     MOST OF THESE ALLOCATION FEATURES ARE IMPLEMENTED THROUGH FLAGS.  READ
  115. THE DOCS BELOW ON OPENIPC() and SENDIPC().
  116.  
  117.  
  118.                APPLICATION NAME DOMAINS
  119.  
  120.     An application for cases (1) or (3) must create a receiver port for
  121. IPC messages with the OpenIPC() call.  OpenIPC() takes a name and flags
  122. argument.  The Flags argument is discussed in OpenIPC() below.  You do
  123. not need a port to send messages, only to receive them.
  124.  
  125.     The name of the port determines the type of messages it will receive.
  126. The format is:    <application_name>.<domain> , for example: "dmouse.CMD"
  127. Currently, only the .CMD domain has a defined standard.  It does not matter
  128. whether multiple copies of the application are running, they can share the
  129. same port name.  You could have, say, two invocations of your favorite
  130. editor each with five active projects.    Support for this is discussed in
  131. the ReplyIPC() call below.
  132.  
  133.     While this port exists, other tasks may send IPC messages to it.  You
  134. must extract the messages (GetMsg()), process it, and then ReplyIPC() the
  135. message to return it to the original sender.
  136.  
  137.     The CloseIPC() call will shutdown an IPC port that you had previously
  138. openning and return any pending messages by trying to pass them to the
  139. next application of the same name (if none, an error is eventually returned
  140. to the sender).
  141.  
  142.                 .CMD ports
  143.  
  144.     Messages sent over .CMD ports are formatted as null-terminated
  145. ascii-text.  The send buffer (msg->TBuf) is formatted as follows:
  146.  
  147.     project\0command\0        (\0 = NUL = ascii 0)
  148.  
  149.     The \0 MUST be included as part of the buffer and buffer length.  The
  150. project name allows the application to identify which of its possibly
  151. multiple projects is to be affected by the command.  a NULL project name
  152. (\0command\0) is allowed and refers to the 'active' project in the
  153. application.  The project name is ignored by applications which do not
  154. support the notion of projects. The format of the command depends on the
  155. application, but must be in ascii and terminate with a \0 (ascii 0).
  156.  
  157.     The logical extension for the specification of multiple project names
  158. is to allow comma delimited names and wildcards (* and ?).  For example,
  159. "*\0command\0" would refer to all projects, "a.c,b.c\0command\0" would
  160. refer to two specific projects.  This might not be supported by all
  161. applications.
  162.  
  163.     The format of the reply buffer depends on the success of the operation.
  164. If the command was successful, the reply buffer will either be NULL or
  165. contain some ascii/text response ending in \0.    If the command was not
  166. successful, IF_ERROR will be set in msg->RFlags and the reply buffer will
  167. be either NULL or contain some ascii/text error message ending in \0.
  168. The msg->Error integer error code will be non-zero if IF_ERROR was set,
  169. possibly non-zero if IF_ERROR was not set to indicate a warning (IF_ERROR
  170. always means Total-Failure).   If msg->Error is not set by the application
  171. which returns the error condition, it will be set by the IPC subsystem.
  172.  
  173.  
  174.  
  175. ParseCmd                            ParseCmd
  176.  
  177.     argc = ParseCmd(buf, &argv, varget, varfree, &error, NULL);
  178.     int argc;
  179.     char **argv;        (note, address passed)
  180.     char *((*varget)());
  181.     void (*varfree)();
  182.     long error;         (note, address passed)
  183.  
  184.     (note:  Last NULL argument (0L) is required for future compatibility).
  185.  
  186.     THIS COMMAND CAN EASILY BE USED WITH NON-IPC RELATED ROUTINES!
  187.  
  188.     Do DME-type parsing on a string buffer.  The buffer is terminated with
  189.     a \0 but may contain a \n at the end (which is ignored) to be compatible
  190.     with fgets() as well as gets().  NOTE that if the string is terminated
  191.     with a \<LF><NUL> i.e. "\\n\0", the backslash will override the standard
  192.     ignorance of the \n and parse it into the result.
  193.  
  194.     DME-type parsing delimites fields by spaces except those enclosed in
  195.     matching parenthesis.  Multiple levels of parenthesis is tracked and
  196.     the OUTERMOST SET REMOVED.    Other special characters include shift-6
  197.     (^), backslash (\), and dollar ($):
  198.  
  199.      form        examples        function
  200.  
  201.     ^<char>     ^c ^d ^L        embed a control character, case is ignored
  202.                     you may not embed ^@ (0)
  203.  
  204.     \<char>     \\ \( \^        override the meaning of the next character,
  205.                     allows embedding special characters.
  206.  
  207.     $(varname)                  inline string variable, var name can be
  208.                     anything except ')'.
  209.  
  210.     $varname            inline string variable, var name
  211.                     restricted to alphanumeric and '_'.
  212.  
  213.     Example:    "echo (this (is a) test) $file/x a mess ^g \(hi! \)ug\\"
  214.     Result: argv[0] =    "echo"
  215.         argv[1] =    "this (is a) test"
  216.         argv[2] =    "dnet:foo/x"        (assumes $file == 'dnet:foo')
  217.         argv[3] =    "a"
  218.         argv[4] =    "mess"
  219.         argv[5] =    "<CONTROL-G>"       (i.e. ascii code 7)
  220.         argv[6] =    "(hi!"
  221.         argv[7] =    ")ug\"
  222.         argv[8] =    NULL
  223.  
  224.     Note: offset -1 of each argument contains a status byte.  Currently,
  225.     bit 0 is defined to indicate whether the argument was paren'd or not.
  226.     This cannot otherwise be told as the highest level of parenthesis are
  227.     stripped.    (argv[0][-1] & 1) == 0, (argv[1][-1] & 1) == 1.
  228.  
  229.                 --------
  230.  
  231.     buf     -\0 or \n\0 terminated buffer holding the command to parse.
  232.          The buffer is not modified and may be discarded after the
  233.          call returns.
  234.  
  235.     &argv    -address of a variable which will be initialized to point
  236.          to an allocated array of pointers to strings exactly the
  237.          way the main() argv works.
  238.  
  239.     varget    -Pointer to a subroutine which when given a \0 terminated
  240.          variable name will return a \0 terminated string or NULL
  241.          if that variable does not exist.
  242.  
  243.          varget(varname)
  244.          char *varname;
  245.  
  246.          This argument may be NULL indicating string variables are
  247.          not supported.  The routine may return non-allocated
  248.          strings (i.e. static storage or string constants) in which
  249.          case there is no need for a varfree() function.
  250.  
  251.     varfree    -Pointer to a subroutine which when given the string
  252.          pointer returned by varget() will free it.  This call
  253.          is made immediately after varget() is called and returns
  254.          nothing.  You may pass NULL for this argument if no free
  255.          function exists (varget was NULL or returned static
  256.          strings).
  257.  
  258.     &error    -You must supply a pointer to a longword which will be
  259.          returned holding the error, if any, and the index where
  260.          the error occured, if any.  The index is stored in the
  261.          lower 16 bits and the error # stored in the upper 16 bits:
  262.  
  263.          1 << 16  = NO MEMORY
  264.          2 << 16  = STRING VARIABLE NOT FOUND (varget() returned
  265.                 NULL), the lower 16 bits contain the index into
  266.                 buf.
  267.  
  268.     NULL    -This argument is reserved for future expansion and must
  269.          be NULL (0L).
  270.  
  271.     NOTE:   The returned arg list may be munged however you wish, including
  272.         the pointers themselves, just as long as you pass the original
  273.         argv pointer (i.e. the entries may be munged) to FreeParseCmd().
  274.  
  275.         0 is always returned on error, and error will be set properly.
  276.         Otherwise, argc is returned and error will hold 0.
  277.  
  278.         The original buffer is not modified in any way.
  279.  
  280.     NOTE:   Since the outer set of parenthesis () are stripped, offset -1
  281.         of each arguments provides information as to whether the
  282.         argument was quoted or not.  If bit 0 is set, the argument
  283.         was quoted,  I.E.:        (a) b c
  284.         (av[0][-1] & 1) = 1     av[0] = "a"
  285.         (av[1][-1] & 1) = 0     av[1] = "b"
  286.         (av[2][-1] & 1) = 0     av[2] = "c"
  287.  
  288.  
  289. FreeParseCmd                            FreeParseCmd
  290.  
  291.     (void) FreeParseCmd(argv)
  292.  
  293.     This routine frees the storage referenced by the argv... the argv array
  294.     and the original strings are all freed.  It is ok if Individual entries
  295.     in the argv array are munged.
  296.  
  297.  
  298. OpenIPC                             OpenIPC
  299.  
  300.     port = OpenIPC(name, flags)
  301.     PORT *port;
  302.     char *name;
  303.     long flags;
  304.  
  305.     Create an IPC port of the specified name suitable for receiving IPC
  306.     commands on.  If the port could not be created due to lack of memory,
  307.     NULL is returned, else an EXEC port is returned.  The port is setup
  308.     as PA_SIGNAL and takes up a signal bit in your signal set.    If the
  309.     application does not wish a signal-port, it may FreeSignal() the
  310.     signal and change the flags to something other than PA_SIGNAL.
  311.  
  312.     Due to the fact that the signal was allocated for the calling task,
  313.     the port is normally usable only from the calling task.  One can
  314.     change the ownership and port characterstics but always remember that
  315.     CloseIPC() can only be called from the owning task.
  316.  
  317.     IF_ALLOC    If IF_ALLOC is specified, *ALL* incomming message buffers
  318.         will be forced to be allocated even if the sender of the
  319.         message specifies IF_NOCOPY.  I.E. you, as the receiver of
  320.         IPC messages on this port can specify this flag to guarentee
  321.         the msg->TBuf is allocated and thus modify the contents
  322.         of the buffer itself without confusing the original sender
  323.         (who may have specified a static string)
  324.  
  325.         Note:    However, if this message is to be passed on via
  326.         IF_GLOBAL or IF_NOTFND, you probably do not want to munge
  327.         the buffer.
  328.  
  329.     IF_GLOBAL    If IF_GLOBAL is specified, this port will accept global
  330.         messages.  Global messages are always of the .CMD form
  331.         though the sender could easily put stuff beyond the second
  332.         \0 in the message buffer destined for specialized routines.
  333.  
  334.         If not specified, IF_GLOBAL messages will NEVER propogate
  335.         through this port.
  336.  
  337.  
  338. CloseIPC                            CloseIPC
  339.  
  340.     (void) CloseIPC(port)
  341.     PORT *port;
  342.  
  343.     Delete an IPC port previously obtained by OpenIPC().  The owning task
  344.     must make this call since it will FreeSignal() the allocated signal.
  345.     Note that if the port flags are set to something other than PA_SIGNAL,
  346.     no attempt will be made to free the possibly non-existant signal bit.
  347.  
  348.     This call will pass any pending messages on to the next application
  349.     of the same name, and if no other exists, will return the messages
  350.     with an error.  Pending messages with IF_GLOBAL set continue their
  351.     journey through the IPC ports flagged to accept IF_GLOBAL messages.
  352.  
  353.  
  354. SendIPC                             SendIPC
  355.  
  356.     msg = SendIPC(appname, buf, len, flags)
  357.     IPCMSG *msg;
  358.     char *appname;
  359.     APTR buf;
  360.     long len, flags;
  361.  
  362.     This routine starts an asynchronous IPC request.  It allocates and
  363.     initializes an IPCMSG and reply port and sends the message to the
  364.     destination application (appname).  The IPCMSG is returned and it's
  365.     msg->RFlags holds the IF_ALLOCMSG internal flag to cause the IPCMSG
  366.     and replyport to be deallocated when you are through with the reply.
  367.     NOTE!  The returned IPCMSG has already been sent to the destination
  368.     and is not owned by you.  The idea is to then CheckMsg() and/or
  369.     WaitMsg() on it.  The ANode filed of the IPCMSG, however, *IS* owned
  370.     by you and you may use it however you wish.
  371.  
  372.     The buffer and buffer length you pass SendIPC() is used to allocate
  373.     a copy of the buffer (which is deallocated automatically when the
  374.     destination ReplyIPC()s).  This means that you can discard/reuse your
  375.     buffer as soon as the call returns.  However, if you specify the
  376.     IF_NOCOPY flag SendIPC() will use your buffer pointer and you must
  377.     be sure not to modify its contents until the message is returned to you.
  378.  
  379.     If you specify IF_ALLOC it is assumed your buffer pointer and length
  380.     were AllocMem()d and the system will FreeMem() them when the destination
  381.     is through processing your message and calls ReplyIPC().
  382.  
  383.     ** See SendIPC2() for info on how to handle the message when it comes
  384.     back.
  385.  
  386.     * If the 'name' is NULL, the first application in the application
  387.     list is called.  This is usually used in conjunction with IF_GLOBAL
  388.     to indicate that the message should propogate to all IPC ports in the
  389.     system.
  390.  
  391. SendIPC2                            SendIPC2
  392.  
  393.     msg = SendIPC2(name, msg)
  394.  
  395.     This routine is called by SendIPC().  This assumes you already have an
  396.     IPC message structure that you wish to use.  The msg argument is
  397.     returned.  The reply fields, including msg->Error and msg->Confirm,
  398.     are zerod.
  399.  
  400.     The IPCMSG must be initialized as follows:
  401.  
  402.     msg->Msg.mn_ReplyPort    -must hold reply port for the message
  403.     msg->Msg.mn_Length        -must hold length of IPCMSG structure ONLY
  404.                  if you had specified the IF_ALLOCMSG in
  405.                  msg->TFlags
  406.     msg->Msg.TBuf        -holds the buffer pointer to the message
  407.                  or NULL
  408.     msg->Msg.TLen        -holds the length of the message
  409.     msg->Msg.TFlags        -holds flags associated with the message:
  410.         IF_ALLOC        * automatic deallocation on reply.  This flag
  411.                   is set automatically if you do not specify
  412.                   IF_NOCOPY.  If NEITHER IF_NOCOPY or IF_ALLOC
  413.                   are specified, the IPC subsystem will
  414.                   allocate a duplicate of your buffer, place
  415.                   it in TBuf, and set this flag for you.
  416.         IF_GLOBAL        * force propogate to all applications in
  417.                   the system before returning to the sender.
  418.         IF_NOCOPY        * force IPC system to use the buffer you
  419.                   placed in TBuf.  Otherwise, the IPC system
  420.                   will allocate and copy your buffer into
  421.                   its own and place that in TBuf.
  422.  
  423.         IF_ALLOCMSG     * IPC system will deallocate the IPCMSG
  424.                   itself when FreeIPC() is called.  This
  425.                   flag is set automatically when the IPC
  426.                   system has allocate the IPCMSG in the
  427.                   first place.
  428.  
  429.     WARNING!    Upon return, msg->TBuf will not necessarily point to your
  430.         buffer, even if you specified IF_NOCOPY or IF_ALLOC.
  431.  
  432.            Handling the message when it comes back
  433.  
  434.     After you make the call, you must wait for the message to complete
  435.     via WaitMsg and/or CheckMsg().  Note that WaitMsg() will remove the
  436.     message from its reply port.  If you do not use WaitMsg(), you must
  437.     remember to remove the message before continuing.
  438.  
  439.     Then, process the reply (msg->RBuf, msg->RLen, and msg->RFlags).
  440.     The msg->RBuf IS ALLOWED TO BE NULL.  msg->RFlags will indicate
  441.     any errors:
  442.  
  443.     IF_ERROR|IF_NOTFND|IF_NOAPP:    no application of that name exists
  444.  
  445.     IF_ERROR|IF_NOTFND       :    application exists, but the requested
  446.                     project does not exist.  OR the
  447.                     command does not exist for this
  448.                     application.
  449.  
  450.     IF_ERROR            :    The application exists and can handle
  451.                     the project & command, but an error
  452.                     occured during interpretation of the
  453.                     command.
  454.  
  455.     IF_ALLOC            :    The reply buffer was allocated.  You
  456.                     have the option of FreeMem()ing it
  457.                     yourself or allowing the system to
  458.                     do so.    If you do it, you must set
  459.                     RBuf = NULL.
  460.  
  461.     NOTE:   msg->Error does not need to be set by the receiver.  If
  462.         msg->Error is 0 and IF_ERROR is set, msg->Error will be set to
  463.         20 by the IPC subsystem.
  464.  
  465.     NOTE:   In the case of IF_ERROR, the reply buffer might still be
  466.         non-NULL and contain an error message.
  467.  
  468.     When through dealing with the reply, you MUST call FreeIPC(msg).  This
  469.     routine will deallocate the reply buffer if msg->RFlags had IF_ALLOC
  470.     set by the destination and also free the message it self if msg->TFlags
  471.     contained IF_ALLOCMSG set by SendIPC() or the user before a SendIPC2().
  472.  
  473.     Additionaly, if msg->Confirm was set by the destination, this function
  474.     vector will be called with the message pointer as an argument to allow
  475.     the destination to deallocate its reply.  NOTE!!! If the message has
  476.     IF_GLOBAL set in msg->TFlags, msg->Confirm should NOT be touched by
  477.     receiving applications.
  478.  
  479.  
  480. DoIPC2                                DoIPC2
  481.  
  482.     (void)  DoIPC2(name, msg, collfunc, collport)
  483.     long flags
  484.     char *name;
  485.     IPCMSG *msg;
  486.     void (*collfunc)();
  487.     PORT *collport;
  488.  
  489.     This is the hall mark of the IPC library and allows one to send
  490.     SEMI-SYNCHRONOUS messages while still retaining the ability to
  491.     process incomming messages on your own IPC port (case #3).  The IPC
  492.     message msg must be setup as in SendIPC2().  The collision function
  493.     and collision port may be NULL if you wish.
  494.  
  495.     This command sends the message and then waits for the reply.  If while
  496.     waiting for the reply a message comes in on the collision port (usually
  497.     your IPC port), the collision vector will be called with the collision
  498.     port as an argument, allowing you to process incomming messages while
  499.     waiting for one you sent.  By properly designing your software, you
  500.     can allow multiply stacked DoIPC2() calls.
  501.  
  502.     When the message finally comes back, this call returns.  The application
  503.     must still deal with its reply buffer and call IPCFree() when through.
  504.  
  505.     NOTE: The collision function is called as a subroutine of this routine
  506.     and thus if it is a general command-handling routine remember that
  507.     your command interpreter might have to be synchronously reentrant.
  508.     DoIPC2() is certainly reentrant.  A4 and A5 are not screwed up by
  509.     DoIPC2() so you do not have to reload your data segment base register
  510.     from the collision vector routine if using the small data model.
  511.     (Compatible with both Aztec and Lattice C).
  512.  
  513.  
  514. ReplyIPC                            ReplyIPC
  515.  
  516.     (void) ReplyIPC(msg, buf, len, flags)
  517.     IPCMSG *msg;
  518.     APTR buf;        (may be NULL & len would then be 0)
  519.     long len;
  520.     long flags;
  521.  
  522.     You must reply to all IPC messages you receive on your IPC port by
  523.     calling ReplyIPC().  ReplyIPC() works almost exactly like IPCSend(),
  524.     but deals with the RBuf, RFlags, and RLen fields of the IPC structure.
  525.     Normally, the IPC system will allocate a duplicate of your reply buffer
  526.     and stick that in msg->RBuf which allows you to throw away your buffer
  527.     after calling ReplyIPC().  Various flags override this feature:
  528.  
  529.     IF_ALLOC        -    The buffer is automatically deallocated when the
  530.             source calls FreeIPC().  If this flag exists the
  531.             IPC system will not allocate a duplicate buffer.
  532.  
  533.     IF_NOCOPY        -    The IPC system will not allocate a duplicate buffer.
  534.  
  535.     Normally, (1) neither of these flags is specified, or (2) IF_ALLOC
  536.     is specified.  Specifying IF_ALLOC alone means that the IPC system
  537.     assumes you have AllocMem()d the buffer yourself and want it
  538.     automatically freed when the source (original sender) calls
  539.     FreeIPC().
  540.  
  541.     Specifying both IF_ALLOC and IF_NOCOPY is equivalent to specifying
  542.     just IF_ALLOC.    Specifying just IF_NOCOPY means that the IPC system
  543.     will use your buffer pointer and will NOT attempt to deallocate it.
  544.     In this case, you are responsible for keeping the buffer intact
  545.     until the source calls FreeIPC().  This is possible through the
  546.     use of the msg->Confirm vector.   ** you cannot use msg->Confirm
  547.     for IF_GLOBAL packets!    Because there is only one vector entry and
  548.     possibly multiple users of the message.
  549.  
  550.     NOTE:  The buffer pointer placed in msg->RBuf will either be yours
  551.     or the allocated duplicate.  msg->RBuf will be set to NULL when (if)
  552.     the system deallocates it.
  553.  
  554.     If you specify IF_NOTFND, your buffer and length are completely
  555.     ignored and the message is passed on to the next application program
  556.     with the same name.  IF THE ORIGINATOR SPECIFIED IF_GLOBAL WHEN HE
  557.     SENT THE MESSAGE, AND YOU DID NOT SPECIFY IF_NOTFND, the message
  558.     will be passed on to the next application anyway and your reply will be
  559.     passed on along with it.  In the same way, if you were not the first
  560.     application to get this message (it was passed to you), the
  561.     msg->RBuf/RLen/RFlags fields may already have something in them. If
  562.     your reply buffer pointer is not the same address as the one already in
  563.     msg->RBuf and msg->RFlags held IF_ALLOC, the old buffer in msg->RBuf
  564.     will be deallocated before processing continues with your ReplyIPC().
  565.  
  566.     ** Warning, msg->RBuf will be replaced in the same manner msg->TBuf
  567.        is by an allocated duplicate unless you specify otherwise.
  568.  
  569.  
  570. FreeIPC                             FreeIPC
  571.  
  572.     (void) FreeIPC(msg)
  573.     IPCMSG *msg;
  574.  
  575.     This routine must be called when the original sender of an IPC message
  576.     has sent the message, waited for the reply, removed the message from
  577.     the reply port, and processed the reply buffer.  This serves to free
  578.     the message and any associated buffers as specified below:
  579.  
  580.     If msg->RFlags has IF_ALLOC set the reply buffer is immediately
  581.     deallocated and msg->RBuf set to NULL.
  582.  
  583.     If msg->Confirm is non-NULL the vector will be called with the IPCMSG
  584.     as an argument.
  585.  
  586.     If msg->TFlags holds IF_ALLOCMSG, the msg will be FreeMem()d with the
  587.     length msg->Msg.mn_Length.    IF_ALLOCMSG is not usually set by the
  588.     user... it is set by SendIPC() which allocates a message/replyport
  589.     and wants both to be deallocated on completion.
  590.  
  591.  
  592.  
  593.  
  594. \Rogue\Monster\
  595. else
  596.   echo "will not over write ipc.doc"
  597. fi
  598. if [ `wc -c ipc.doc | awk '{printf $1}'` -ne 24710 ]
  599. then
  600. echo `wc -c ipc.doc | awk '{print "Got " $1 ", Expected " 24710}'`
  601. fi
  602. if `test ! -s lists.doc`
  603. then
  604. echo "writing lists.doc"
  605. cat > lists.doc << '\Rogue\Monster\'
  606.  
  607.                  LISTS.DOC
  608.  
  609.     These are general list handling routines that should have been provided
  610. in EXEC.  In addition to basic additions, I provide support for structures
  611. whos Nodes are not at the base of the structure.  These are the infamous
  612. 'sptr's below.  Such routines take a pointer to the structure, add an
  613. offset to it to get to the Node, do the specified operation, then subtract
  614. the offset to return to the 'sptr's actual base.  In otherwords, it allows
  615. you to deal with such structures without having to do these hacks in your
  616. source.
  617.  
  618. GetHead                             GetHead
  619. GetSucc                             GetSucc
  620.  
  621.     node = GetHead(list)
  622.     node = GetSucc(node)    (physically the same routine as GetHead()).
  623.  
  624.     This routine returns the successor of a node in the list.  If a list is
  625.     specified, the first node in the list is returned.    NULL is returned if
  626.     the list is empty or one has reached the end of the list.
  627.  
  628. GetTail                             GetTail
  629.  
  630.     node = GetTail(list)
  631.  
  632.     This routine returns the last node in the list, or NULL if the list
  633.     is empty.
  634.  
  635. GetPred                             GetPred
  636.  
  637.     node = GetPred(node)
  638.  
  639.     This routine returns the previous node from the given node, or NULL
  640.     if we are at the head of the list.
  641.  
  642. GetHeadOff                            GetHeadOff
  643.  
  644.     sptr = GetHeadOff(list, offset)
  645.  
  646.     This routine retrieves the first node in the list and subtracts the
  647.     specified offset to get to the base of the structure (where 'offset'
  648.     is the offset into the structure where the Node has been placed rather
  649.     than placing it as the first object in the structure).
  650.  
  651.     NULL is returned is the list is empty.  NOTE!  Unlike GetHead(), only
  652.     a valid list pointer may be specified here.
  653.  
  654. GetTailOff                            GetTailOff
  655.  
  656.     sptr = GetTailOff(list, offset)
  657.  
  658.     This routine works the same as GetHeadOff() but works on the last
  659.     node in the list.
  660.  
  661. GetSuccOff                            GetSuccOff
  662.  
  663.     sptr = GetSuccOff(sptr, offset)
  664.  
  665.     Given a structure pointer where the Node is offset from the structure
  666.     base, add the offset to the pointer, determine the successor if any,
  667.     then subtract the offset from the successor to get back to the
  668.     structure base for the successor.
  669.  
  670.     NULL is returned if there is no successor.
  671.  
  672. GetPredOff                            GetPredOff
  673.  
  674.     sptr = GetPredOff(sptr, offset)
  675.  
  676.     This routine works the same as GetSuccOff() but works on the previous
  677.     node rather than the next.    NULL is returned if we are at the head
  678.     of the list;
  679.  
  680. EnqueueLong                            EnqueueLong
  681.  
  682.     (void) EnqueueLong(list, startnode, node, valoff)
  683.  
  684.     This routine queues a node into a list beginning its search at the
  685.     startnode (first element if startnode == NULL).  The list is assumed
  686.     to be sorted by the longword valoff from the node structure.  I.E.
  687.     If you had a graphic structure with a Node at its base and where
  688.     coordinates were stored in longwords, you insert nodes sorted by
  689.     one of the coordinates into a list.
  690.  
  691.     valoff is the offset from the node base where the longword value
  692.     the list is sorted by exists.
  693.  
  694. EnqueueOffLong                            EnqueueOffLong
  695.  
  696.     (void) EnqueueOffLong(list, startnode, sptr, off, valoff)
  697.  
  698.     This works just like EnqueueLong() but an extra parameter, 'off', is
  699.     provided to inform the routine where in the structure the Node is.
  700.     Does that make sense?
  701.  
  702. SearchFwdNode                            SearchFwdNode
  703.  
  704.     retval = SearchFwdNode(node, function, arg)
  705.     MINNODE *node;
  706.     long (*function)();
  707.     long arg;
  708.  
  709.     This routine searches a list in the forward direction beginning at
  710.     the specified node, calling the function vector for every node.  The
  711.     function is called C-fashion (A4 and A5 are intact to support the
  712.     small code model and D2/D3 may be destroyed in addition to standard
  713.     scratch variables to support Aztec C).  The function is given two
  714.     arguments:    the node, and the arg passed to SearchFwdNode():
  715.  
  716.     (*function)(current_srch_node, arg)
  717.  
  718.     The search is terminated if the function vector returns a non-zero
  719.     value.  If the search reaches the end of the list, NULL is returned.
  720.     NOTE: you may pass a NULL as the node to SearchFwdNode() which results
  721.     in a NULL being immediately returned.
  722.  
  723. SearchRvsNode                            SearchRvsNode
  724.  
  725.     retval = SearchFwdNode(node, function, arg)
  726.  
  727.     This function works exactly the same as SearchFwdNode() but works
  728.     in reverse begining at the specified node.
  729.  
  730. SearchFwdList                            SearchFwdList
  731.  
  732.     retval = SearchFwdList(list, function, arg)
  733.  
  734.     This function works exactly the same as SearchFwdNode() but you give
  735.     it a pointer to a list rather than to a node.
  736.  
  737.     A valid list pointer must be specified, but the list may be empty.
  738.  
  739. SearchRvsList                            SearchRvsList
  740.  
  741.     retval = SearchRvsList(list, function, arg)
  742.  
  743.     This function works exactly the same as SearchRvsNode() but you give
  744.     it a pointer to a list rather than to a node.
  745.  
  746.     A valid list pointer must be specified, but the list may be empty.
  747.  
  748. SearchFwdNodeOff                        SearchFwdNodeOff
  749. SearchRvsNodeOff                        SearchRvsNodeOff
  750. SearchFwdListOff                        SearchFwdListOff
  751. SearchRvsListOff                        SearchRvsListOff
  752.  
  753.     rval    =    SearchFwdNodeOff(sptr, function, off, arg)
  754.     rval    =    SearchRvsNodeOff(sptr, function, off, arg)
  755.     rval    =    SearchFwdListOff(list, function, off, arg)
  756.     rval    =    SearchRvsListOff(list, function, off, arg)
  757.  
  758.     These routines work like those shown above, but an additional
  759.     argument, an offset, is supplied.  This is the offset into the
  760.     structure pointer where the Node structure is embedded.  In otherwords,
  761.     the other routines were simply special cases of this one with off == 0.
  762.  
  763.     Note that for *NodeOff() routines a pointer to a structure containing
  764.     the Node structure in it somewhere is supplied, whereas in the
  765.     *ListOff() routines a pointer to the list base is given (this hasn't
  766.     changed).
  767.  
  768.  
  769.  
  770. \Rogue\Monster\
  771. else
  772.   echo "will not over write lists.doc"
  773. fi
  774. if [ `wc -c lists.doc | awk '{printf $1}'` -ne 5861 ]
  775. then
  776. echo `wc -c lists.doc | awk '{print "Got " $1 ", Expected " 5861}'`
  777. fi
  778. if `test ! -s memory.doc`
  779. then
  780. echo "writing memory.doc"
  781. cat > memory.doc << '\Rogue\Monster\'
  782.  
  783.                 MEMORY.DOC
  784.  
  785.     These are general memory handling routines which will perform operations
  786.     as quickly as possible.  They are super-optimized to use long word and
  787.     multiple-register moves whenever possible.
  788.  
  789. BZero                                    BZero
  790.  
  791.     (void) = BZero(buf, bytes)
  792.     APTR buf;
  793.     long bytes;
  794.  
  795.     Zero out an area of memory.  That was simple!  This is simply a special
  796.     case of BSet()
  797.  
  798. BSet                                    BSet
  799.  
  800.     (void) = BSet(buf, bytes, value)
  801.     APTR buf;
  802.     long bytes;
  803.     long value;     (only lower 8 bits used)
  804.  
  805.     Jam a byte value into an area of memory.
  806.  
  807.  
  808. BMov                                    BMov
  809.  
  810.     (void) = BMov(src, dest, bytes)
  811.     APTR src, dest;
  812.     long bytes;
  813.  
  814.     Move a block of memory from the source to the destination.    An
  815.     ascending or decending copy is used depending on how the source and
  816.     destination overlap, if at all.  Both are optimized to use multiple-
  817.     register moves when possible, longword moves, or byte moves if the
  818.     two blocks are hopelessly out of alignment.
  819.  
  820. BCmp                                    BCmp
  821.  
  822.     BOOL   = BCmp(src, dest, bytes)
  823.     APTR src, dest;
  824.     long bytes;
  825.  
  826.     Compare two blocks of memory.  (1) is returned on success, (0) on
  827.     failure.  Currently, this routine is not optimized at all.
  828.  
  829.  
  830. \Rogue\Monster\
  831. else
  832.   echo "will not over write memory.doc"
  833. fi
  834. if [ `wc -c memory.doc | awk '{printf $1}'` -ne 1234 ]
  835. then
  836. echo `wc -c memory.doc | awk '{print "Got " $1 ", Expected " 1234}'`
  837. fi
  838. if `test ! -s misc.doc`
  839. then
  840. echo "writing misc.doc"
  841. cat > misc.doc << '\Rogue\Monster\'
  842.  
  843.                   MISC.DOC
  844.  
  845.     These are miscellanious useful routines for your enjoyment.
  846.  
  847.  
  848. WildCmp                             WildCmp
  849.  
  850.     CBOOL  = WildCmp(wildcard, filename)
  851.     char *wildcard;
  852.     char *filename;
  853.  
  854.     The wildcard characters supported are * and ?.  The wildcard is
  855.     compared against the filename and (1) returned on success, (0) on
  856.     failure.
  857.  
  858.  
  859. WaitMsg                             WaitMsg
  860.  
  861.     msg    = WaitMsg(msg)
  862.     EXECMSG *msg;
  863.  
  864.     This routines Waits for a message to be returned just like WaitIO()
  865.     waits for an io request to complete.  The message is REMOVED from the
  866.     reply port after it has returned.
  867.  
  868.     the message must have a valid mn_ReplyPort() and must have been queued
  869.     with PutMsg(), which sets the ln_Type to NT_MESSAGE, and replied with
  870.     ReplyMsg(), which sets the ln_Type to NT_REPLYMSG.
  871.  
  872.  
  873. CheckMsg                            CheckMsg
  874.  
  875.     msg/NULL = CheckMsg(msg)
  876.     EXECMSG *msg;
  877.  
  878.     This routine checks to see if the message has been returned.  The
  879.     same restrictions apply as for WaitMsg().  the message is NOT removed.
  880.     The message is returned if it has been returned (not removed), or
  881.     NULL otherwise.
  882.  
  883.  
  884. CheckPort                            CheckPort
  885.  
  886.     msg/NULL = CheckPort(port)
  887.     EXECMSG *msg;
  888.     PORT *port;
  889.  
  890.     This routine works like WaitPort(), but (1) does not block, and
  891.     (2) does not remove the message.  If the port is not empty the first
  892.     message is returned (not removed), else NULL is returned if the port
  893.     is empty.
  894.  
  895.  
  896. LockAddr                            LockAddr
  897.  
  898.     (void) LockAddr(&lock)
  899.     long lock[2];
  900.  
  901.     The lock structure (8 bytes) MUST initially be 0.  This routine obtains
  902.     an exclusive lock on the structure and blocks until that lock can be
  903.     obtained.  The structure must be word-aligned.
  904.  
  905.     Unless it is forced to block, this subroutine is extremely fast.  This
  906.     routine does not allocate any signals, but uses the reserved EXEC
  907.     semaphore signal.
  908.  
  909.  
  910. LockAddrB                            LockAddrB
  911.  
  912.     (void) LockAddr(bitno, &lock)
  913.     long bitno;
  914.     long lock[2];
  915.  
  916.     The lock structure actually supports up to 8 independant exclusive
  917.     locks.  LockAddr() is a special case which uses bit # 0.  This call
  918.     works as in LockAddr() but you may specify the bit you wish to lock
  919.     (0 to 7).  If you specify 0, this call is equivalent to LockAddr().
  920.  
  921.  
  922. UnLockAddr                            UnLockAddr
  923.  
  924.     (void) UnLockAddr(&lock)
  925.     long lock[2];
  926.  
  927.     Remove an exclusive lock you had previously obtained.  If other tasks
  928.     are waiting for this lock, ALL are awakened even though only one will
  929.     get the lock next.    This ensures that the highest priority task will
  930.     get the lock next.
  931.  
  932.     This routine is extremely fast if nobody else is waiting for the lock,
  933.     else it has to Signal() them.  You MUST have previously obtained the
  934.     lock.
  935.  
  936.  
  937. UnLockAddrB                            UnLockAddrB
  938.  
  939.     (void) UnLockAddrB(bitno, &lock)
  940.     long bitno;
  941.     long lock[2];
  942.  
  943.     Again, this routine works the same as UnLockAddr() with the exception
  944.     that you may specify one of the 8 bits to unlock (0 to 7).
  945.  
  946.  
  947. DoSyncMsg                            DoSyncMsg
  948.  
  949.     (void) DoSyncMsg(port, msg)
  950.     PORT *port;
  951.     EXECMSG *msg;
  952.  
  953.     This routine PutMsg()s a message and waits for it to be returned.  This
  954.     routine creates its own reply port on the stack and stuffs it into
  955.     mn_ReplyPort for you.  Thus, virtually no setup is required to use
  956.     this routine.
  957.  
  958.  
  959. FindName2                            FindName2
  960.  
  961.     node/NULL = FindName2(list, name)
  962.  
  963.     This routine is identical to the EXEC FindName() call with the exception
  964.     that it ignores nodes whos ln_Name fields are NULL.  ln_Name fields in
  965.     the list nodes must contain either NULL or a valid string pointer.
  966.  
  967.  
  968. GetTaskData                            GetTaskData
  969.  
  970.     ptr = GetTaskData(name, bytes)
  971.     APTR ptr;
  972.     char *name;
  973.     long bytes;
  974.  
  975.     This routine retrieves/allocates task-private named storage.  For a
  976.     specific name, the first GetTaskData() call will allocate the specified
  977.     # of bytes and zero them.  Space to hold the name itself is also
  978.     allocated (i.e. you can use a temporary buffer to hold 'name' when you
  979.     make this call).  Future calls return the pointer to the already
  980.     allocated storage without modifying it.
  981.  
  982.     The storage is automatically freed if the TASK is removed... note that
  983.     the task is not normally removed when a C program exits back into a
  984.     CLI enviroment... it uses the CLI's task to run the program.  The
  985.     task's memory list is used to implement this function.
  986.  
  987.  
  988. FreeTaskData                            FreeTaskData
  989.  
  990.     (void) FreeTaskData(name)
  991.     char *name;
  992.  
  993.     If the task-private name exists, the storage associated with it is
  994.     freed.  This works with memlist entries allocated with GetTaskData()
  995.     or by the user, assuming the ln_Name field points to a valid string.
  996.  
  997.     (note:  FreeEntry() is used after the associated MemList structure is
  998.      unlinked frlom the list.  ln_Name is not specifically freed but the
  999.      way GetTaskData() works, the second entry is actually the storage
  1000.      associated with the ln_Name)
  1001.  
  1002.  
  1003. \Rogue\Monster\
  1004. else
  1005.   echo "will not over write misc.doc"
  1006. fi
  1007. if [ `wc -c misc.doc | awk '{printf $1}'` -ne 4956 ]
  1008. then
  1009. echo `wc -c misc.doc | awk '{print "Got " $1 ", Expected " 4956}'`
  1010. fi
  1011. if `test ! -s qints.doc`
  1012. then
  1013. echo "writing qints.doc"
  1014. cat > qints.doc << '\Rogue\Monster\'
  1015.  
  1016.                  QINTS.DOC
  1017.  
  1018.     I call them Q-Interrupts to tell them apart from other types of
  1019. interrupts that exist on the Amiga.  QInts provide a general purpose
  1020. priority enhanced local task-interrupt system based on exceptions.
  1021.  
  1022.     Essentially, one can associate a Q interrupt with any set of EXEC
  1023. signals.  When an associated signal comes in, a Q interrupt occurs.  The
  1024. interrupt is taken immediately if the current task Q-priority is lower
  1025. than the Q-priority of the interrupt, else it is queued until the
  1026. priority becomes lower.
  1027.  
  1028.     When a Q-interrupt is taken, the task's Q-priority is raised to that
  1029. of the Q-interrupt while the interrupt is being processed.  Additionaly,
  1030. the application software may set the task's Q-priority at any time,
  1031. usually to prevent interrupts from occuring in critical sections.
  1032.  
  1033. OpenQInts                            OpenQInts
  1034.  
  1035.     handle = OpenQInts()
  1036.     long handle;
  1037.  
  1038.     This routine initializes a handle for the Q interrupt system.  All
  1039.     32 EXEC signals may be controlled through this one handle.    NULL is
  1040.     returned on error, else a non-zero handle is returned.
  1041.  
  1042. CloseQInts                            CloseQInts
  1043.  
  1044.     (void) = CloseQInts(handle)
  1045.     long handle;
  1046.  
  1047.     This routine shuts down the handle, including the removal of any
  1048.     active Q Interrupt vectors.
  1049.  
  1050. SetQPri                             SetQPri
  1051.  
  1052.     (void) = SetQPri(handle, pri)
  1053.     long handle;
  1054.     long pri;
  1055.  
  1056.     This routine sets the current Q-interrupt priority for the task...
  1057.     actually all interrupts associated with the handle but this is
  1058.     usually all the interrupts period.
  1059.  
  1060.     Any Q-interrupts with higher priority can occur, while interrupts
  1061.     with lower or equal priority will be queued until you SetQPri() to
  1062.     a lower value.
  1063.  
  1064.     'pri' has a range -127 to 127
  1065.  
  1066. SetQVector                            SetQVector
  1067.  
  1068.     oldvec = SetQvector(handle, vector, signo, arg, pri)
  1069.     void (*oldvec)();
  1070.     void (*vector)();
  1071.     long handle;
  1072.     long signo;
  1073.     long arg;
  1074.     long pri;
  1075.  
  1076.     This routine applied or removes or changes the priority of a
  1077.     Q interrupt.  If vector is NULL, the interrupt is removed for the
  1078.     specified signo.  If vector is not NULL the interrupt is set for
  1079.     the specified signo, replacing any previous interrupt vector and
  1080.     priority that existed.
  1081.  
  1082.     The interrupt has a priority of 'pri', (-127 to 127).
  1083.  
  1084.     The vector may be a C routine.  The OpenQInts() routine saved A4/A5
  1085.     and these registers are automatically re-loaded before the vector
  1086.     is called to support the small-data model.    Additionaly, D2 and D3
  1087.     Parameters are also scratch to support Aztec C.  Both Aztec and Lattice
  1088.     C are thus supported.  Parameters to the service routine are passed on
  1089.     the stack:
  1090.  
  1091.     (*vector)(arg)
  1092.  
  1093.     Specifically, the argument you gave SetQVector().
  1094.  
  1095.     NOTE:   SetQVector() may be called from a Q-interrupt.
  1096.  
  1097.  
  1098. \Rogue\Monster\
  1099. else
  1100.   echo "will not over write qints.doc"
  1101. fi
  1102. if [ `wc -c qints.doc | awk '{printf $1}'` -ne 2789 ]
  1103. then
  1104. echo `wc -c qints.doc | awk '{print "Got " $1 ", Expected " 2789}'`
  1105. fi
  1106. if `test ! -s res.doc`
  1107. then
  1108. echo "writing res.doc"
  1109. cat > res.doc << '\Rogue\Monster\'
  1110.  
  1111.  
  1112.                   RESOURCE.DOC
  1113.  
  1114.            AMIGA RESOURCES AS IMPLEMENTED BY DRES.LIBRARY
  1115.  
  1116.     The first order of business is to avoid some confusion.  The Amiga
  1117.     already has resources .... EXEC resources, which are used mainly to
  1118.     arbitrate low level hardware.  The resources I am talking about is an
  1119.     object oriented system and has nothing to do with EXEC resources.  All
  1120.     references to 'resources' in this document refer to this object
  1121.     oriented system.
  1122.  
  1123.     What is a resources?  A resource is a means of accessing one or more
  1124.     objects through a generalized interface with as much flexibility as
  1125.     possible.  A specific object in this system has certain capabilities
  1126.     and is referenced by a pointer to something.  For instance, an
  1127.     intuition Window could be a resource.  Each and every resource in the
  1128.     system may be flagged as follows (any combination of flags):
  1129.  
  1130.     SHARABLE    -   Multiple references to the resource are allowed.  If not
  1131.             sharable, duplication of a resource results in two
  1132.             distinct resources with different data areas rather
  1133.             than two pointers to a shared data area.
  1134.  
  1135.             Duplication of non-sharable resources via DupRes()
  1136.             results in a copy of that resource's data including any
  1137.             changes made to that data.    GetRes()ing it results in
  1138.             a pristine copy.
  1139.  
  1140.             Duplication of a shareable resource returns the common
  1141.             data area whether you DupRes() it or GetRes() it.
  1142.  
  1143.     GLOBAL    -   A global resource can be accessed by any task in the
  1144.             system.  NOTE:  Private resources can still be
  1145.             sharable, but only by a DupRes() call or a GetRes()
  1146.             call from a task's private resource list.
  1147.  
  1148.             Also, any resources tagged as GLOBAL in a task's private
  1149.             resource list are immediately accessable to other tasks
  1150.             via GetRes().  Searching other task's private lists for
  1151.             global resources is always done last.
  1152.  
  1153.     VIRTUAL    -   A virtual resource is one that has been algorithmically
  1154.             generated.    Most resources are virtual resources.  For
  1155.             example, an intuition Window would be a virtual resource.
  1156.  
  1157.             Non virtual resources are the 'raw' resources on disk.
  1158.             For instance, a "_List" resource would be a raw resource
  1159.             but when you GetRes(name, "List") note that obviously
  1160.             some conversion code is required to go from "_List" to
  1161.             "List", in this case the code initializes the list
  1162.             pointers.
  1163.  
  1164.             Most of the time, the existance of one or more
  1165.             algorithms (subroutines) to generate a resource is
  1166.             completely transparent to the routine requesting the
  1167.             resource.  Using the above example, the task requesting
  1168.             the resource simply asks for a "List" and is oblivious
  1169.             to what actually must be performed to give him that
  1170.             List.
  1171.  
  1172.     SWAPABLE    -   While not being referenced (all references fall to 0),
  1173.             rather than delete the resource, it should be swapped to
  1174.             disk (read: any filesystem device) and then swapped
  1175.             back in when accessed.  This does not mean a resource
  1176.             is automatically swapped when references fall to 0,
  1177.             just that it *might* be swapped.
  1178.  
  1179.             This only applies to SHARABLE resources, as you cannot
  1180.             DupRes() a non-shared resource when the references fall
  1181.             to 0 (nothing to dup), and GetRes() returns a pristine
  1182.             copy.
  1183.  
  1184.             SHARABLE resources on the otherhand are assumed to be
  1185.             of a more permanent nature.  As in the LOCKED flag
  1186.             below, this flag guarentees the resource will not become
  1187.             pristine on the next reference after previous usage.
  1188.  
  1189.     LOCKED    -   While not being referenced, rather than delete or swap
  1190.             the resource, it should stay in memory.  This only
  1191.             applies to SHARABLE resources.
  1192.  
  1193.  
  1194.             RESOURCE NAMES AND ALGORITHMIC GENERATION
  1195.  
  1196.     The identification of a resource consists of two parts.  (1) The name
  1197.     of the resource, and (2) the structure of the resource.  The name of
  1198.     the resource is arbitrary while the structure of the resource is some
  1199.     agreed upon standard.  The two parts are stuck together with an
  1200.     intervening period like so:
  1201.  
  1202.         CHArlIE.Window
  1203.  
  1204.     For the above example, we have a resource named 'CHArlIE' of structure
  1205.     'Window'... an intuition window pointer would be the result of
  1206.     accessing this particular resource.  However, it is not possible to
  1207.     store a Window structure on disk verbatim since there are lots of
  1208.     pointers and other dependancies with intuition.  On disk, the resource
  1209.     might actually be:
  1210.  
  1211.         CHArlIE.NewWindow
  1212.  
  1213.     But we want a Window structure... if the program requests
  1214.     CHArlIE.Window there must be some means of algorithmically translating
  1215.     a NewWindow to a Window.  These algorithms are provided by yet a
  1216.     third resource named:
  1217.  
  1218.         NewWindow.Window.CODE
  1219.  
  1220.     The name is 'NewWindow.Window' and the type is 'CODE'.  This resource
  1221.     is a procedure which translates a NewWindow to a Window by calling
  1222.     OpenWindow().  The translation procedure is recursive, thus allowing
  1223.     any manner of 'patching' for reasons given above, for maintaining
  1224.     compatibility with older structures, and for convenience.
  1225.  
  1226.     Finally, a resource is owned by a specific task.  One can pass
  1227.     resources around but it must be done with cooperation from the
  1228.     library.
  1229.  
  1230.     CODE resources are discussed later on.  Now that you have an idea how
  1231.     resources work, we shall discuss the library calls currently available:
  1232.  
  1233.  
  1234.  
  1235.                RESOURCE LIBRARY CALLS
  1236.  
  1237.     Beginning with the easiest of the calls and ending with the more
  1238.     difficult.    NOTE: Resource names are limited to 31 characters,
  1239.     Resource types are limited to 31 characters.
  1240.  
  1241.     resptr= GetRes(resnametype)             char *resnametype;
  1242.  
  1243.     This function retrieves the requested resource, doing any
  1244.     translations required to get the resource into the requested
  1245.     type.  NULL is returned if the resource could not be found
  1246.     or could not be translated to the requested type.
  1247.  
  1248.     In-Memory private resources are searched first, then the private
  1249.     resource files for the task, then In-Memory system resources, then
  1250.     the global resource files for the system.  Openning an already-open
  1251.     resource causes one of two actions depending on whether the resource
  1252.     is shared or not.  If shared, the reference count is simply
  1253.     incremented, otherwise a private copy of the resource is made.
  1254.  
  1255.     Example:    Win = GetRes("Charlie.Window");
  1256.  
  1257.     resptr2 = DupRes(resptr1)               APTR resptr1, resptr2;
  1258.  
  1259.     This call duplicates a resource.  If the resource is shared
  1260.     resptr2 will be the same as resptr1 and the reference count will
  1261.     be bumped.  Otherwise, a new resource data area is allocated and
  1262.     the old copied to the new.
  1263.  
  1264.     Things like fixing pointers and such within a resource that is
  1265.     physically duplicated are handled by the interface code (since
  1266.     raw resources do not contain pointers, only VIRTUAL resources
  1267.     will contain pointers and all VIRTUAL resources have some
  1268.     interface code).
  1269.  
  1270.     error = FreeRes(resptr)
  1271.  
  1272.     Free a resource that you retrieved via GetRes().  Only the task
  1273.     that owns the resource may free it (though several tasks may own
  1274.     a resource through duplication and ownership changes).    1 is
  1275.     returned on success, 0 on error.
  1276.  
  1277.     That is, if task #1 GetRes()'s the resource and duplicates it once,
  1278.     then task #2 duplicates it once, task #1 must call FreeRes() twice
  1279.     and task #2 must call FreeRes() once.  Ownership is strictly
  1280.     tracked.
  1281.  
  1282.     numres= FreeAllRes(task)
  1283.  
  1284.     Free all resources associated with the specified task (NULL for
  1285.     self).
  1286.  
  1287.     error = ChownRes(resptr, fromtask, totask)
  1288.  
  1289.     Change ownership of a resource from the source task to the
  1290.     destination task.  The resource must be owned by the source
  1291.     task or an error will occur (0 return value).  1 is returned
  1292.     on success.  NULL may be specified for either or both tasks
  1293.     and means the calling task.
  1294.  
  1295.     handle= UnLinkAllRes(task)
  1296.  
  1297.     Unlink all resources associated with the specified task (NULL
  1298.     for self) and return a handle representing those resources.
  1299.  
  1300.     This is useful for shells and such to keep their resources from
  1301.     getting removed by commands they run.  Combined with the NUNLINK
  1302.     flag one can pass resources to a Command and keep the rest out of
  1303.     reach.
  1304.  
  1305.     (void)  ReLinkAllRes(handle, task)
  1306.  
  1307.     Link all the resources represented by the handle to the specified
  1308.     task (NULL for self).
  1309.  
  1310.     oldfl = SetResFlags(resptr, newflags, flagsmask)
  1311.  
  1312.     Modify the flags associated with a resource.  NOTE:  If multiple
  1313.     references to a shared resource exist, all are modified.  Some
  1314.     modifications may be disallowed by the system.    This call is
  1315.     normally used to modify the LOCKED and SWAPABLE flags (note that
  1316.     the SWAPABLE flag can be changed back and forth only for resource
  1317.     which support it).
  1318.  
  1319.     error = AddRes(resnametype, flags, ptr, ctlcode);
  1320.                             char *resnametype;
  1321.                             long flags;
  1322.                             APTR ptr;
  1323.                             long (*ctlcode)();
  1324.  
  1325.     Add a resource to the system.  The resource is placed either in
  1326.     the task's privately accessable in-memory resource list or
  1327.     in the system global accessable in-memory resource list depending
  1328.     on the specified flags.  One may now GetRes() the resource.
  1329.  
  1330.     ONLY VIRTUAL RESOURCES MAY BE ADDED IN THIS WAY.  The VIRTUAL
  1331.     and LOCKED flags are automatically set.
  1332.  
  1333.     If flags specifies a VIRTUAL resource
  1334.  
  1335.     error = RemRes(resname)
  1336.  
  1337.     Remove the specified resource.    An error will occur and the resource
  1338.     will not be removed (1) if it does not exist in memory, or (2) it
  1339.     is currently being referenced.    (Note: the resource is removed even
  1340.     if it is swapped or locked).
  1341.  
  1342.     error = GetResInfo(resname, &flags, &bytes)
  1343.  
  1344.     Get information on a resource.    Information may not exist for a
  1345.     resource if it is not currently in memory and would have to be
  1346.     translated to get to the right type.
  1347.  
  1348.     error = GetResList(wildcard, from, &av, &ac);
  1349.  
  1350.     from:    mask, bit 0  search private list
  1351.               1  search system list
  1352.               2  <not used>
  1353.               3  search in-memory private list
  1354.               4  search in-memory global list
  1355.  
  1356.     Return an ARGC/ARGV list of resource names.  Note that some names
  1357.     might be duplicated if searching multiple lists.  Restricting the
  1358.     search to in-memory lists give resources which are already in
  1359.     memory (but might be swapped out or removed at any time for those
  1360.     with no references)
  1361.  
  1362.                  RESOURCE FILES
  1363.  
  1364.     error = GetFileList(wildcard, from, &av, &ac);
  1365.  
  1366.     from:    mask, bit 0  search private list
  1367.               1  search system list
  1368.               2  search swap list
  1369.  
  1370.     Return an ARGC/ARGV list of the files which match the specified
  1371.     wildcard from the private list, system list, or system swap dir
  1372.     list (in which case you get directory names).  This list has been
  1373.     allocated, and can be freed as follows:
  1374.  
  1375.         Loop through all entries for (i = 0; i < ac; ++i)
  1376.                     FreeMem(av[i], strlen(av[i])+1);
  1377.         Free the array itself:  FreeMem(av, sizeof(char *) * (ac+1));
  1378.  
  1379.     num   = AddPrivResFile(filename, pri)
  1380.  
  1381.     Add a file name to the list of resource files for this task.  These
  1382.     are scanned before global files when a resource is requested.  All
  1383.     files in the list are write protected (i.e. a shared lock is kept
  1384.     for each file).  Thus, such files cannot be updated until removed
  1385.     from the list.
  1386.  
  1387.     Can also be used to modify the priority of an existing file
  1388.  
  1389.     num   = RemPrivResFiles(wildcard)
  1390.  
  1391.     Remove zero or more file names from the list of resource files for
  1392.     this task.  A wildcard pattern (* and ?) is accepted.
  1393.  
  1394.     Note for command processors:    commands you run might execute
  1395.     this command for *.
  1396.  
  1397.     num   = AddGlobResFile(filename, pri)
  1398.  
  1399.     Same as AddPrivResFile() but applies to the system list, which is
  1400.     searched last and by any requesting task.  Wildcard file names are
  1401.     NOT accepted.  The file need not exist at this time, and references
  1402.     to unmounted volumes are allowed.
  1403.  
  1404.     Can also be used to modify the priority of an existing entry
  1405.  
  1406.     num   = RemGlobResFiles(wildcard)
  1407.  
  1408.     Remove zero or more resource files from the global list.  Again,
  1409.     a wildcard filename is accepted.
  1410.  
  1411.     num   = AddResSwapDir(dirname, pri, maxkbytes)      char *dirname;
  1412.                             char pri;
  1413.                             long maxkbytes
  1414.  
  1415.     Add a directory to the list of directories the resource system
  1416.     can swap to.  The maximum number of KBytes of material allowed
  1417.     in the directory should be specified.  You can also use this
  1418.     call to modify the priority and maxkbytes for an entry.
  1419.  
  1420.     The highest priority directories are used before lower priority
  1421.     directories.  Not all directories need be mounted, but if a swapin
  1422.     occurs from an unmounted directory a requester will appear.
  1423.  
  1424.     A lock is kept on each specified directory.
  1425.  
  1426.     num   = RemResSwapDirs(wildcard)
  1427.  
  1428.     Remove directories associated with the resource swap areas.
  1429.  
  1430.  
  1431.                 RESOURCE FILE IFF FORMAT
  1432.  
  1433.  
  1434. \Rogue\Monster\
  1435. else
  1436.   echo "will not over write res.doc"
  1437. fi
  1438. if [ `wc -c res.doc | awk '{printf $1}'` -ne 12714 ]
  1439. then
  1440. echo `wc -c res.doc | awk '{print "Got " $1 ", Expected " 12714}'`
  1441. fi
  1442. if `test ! -s runlib.doc`
  1443. then
  1444. echo "writing runlib.doc"
  1445. cat > runlib.doc << '\Rogue\Monster\'
  1446.  
  1447.                 DRES.LIBRARY
  1448.  
  1449.                 OVERVIEW OF FUNCTIONS
  1450.  
  1451.     This document is meant to give a simple overview of library functions,
  1452.     not to provide complete explanations.  Please refer to the separate
  1453.     document files for various command groups for more detailed information.
  1454.  
  1455.     * All function arguments are 32 bits unless otherwise specified
  1456.  
  1457.     * Any Address register may be used to hold the library base pointer
  1458.       when calling library routines from assembly.
  1459.  
  1460.  
  1461.                   IPC
  1462.  
  1463.     ipcport =    OpenIPC(name, 0)
  1464.     (void)  =   CloseIPC(ipcport)
  1465.     ipcmsg  =    SendIPC(name, buf, len, flags)
  1466.     ipcmsg  =    SendIPC2(name, ipcmsg)
  1467.     (void)  =   ReplyIPC(msg, buf, len, flags)
  1468.     (void)  =   FreeIPC(msg)
  1469.     (void)  =   DoIPC2(name, msg, handler, ipcport)
  1470.  
  1471.     argc    =    ParseCmd(str, &argv, varget, varfree, &error, NULL)
  1472.         FreeParseCmd(argv)
  1473.  
  1474.                  QINTS
  1475.  
  1476.     handle  =    OpenQInts()
  1477.     (void)  =   CloseQInts(handle)
  1478.     (void)  =   SetQPri(handle, pri)
  1479.     oldvect =    SetQVector(handle, vector, signo, arg, pri)
  1480.  
  1481.                  MISC
  1482.  
  1483.     BOOL    =    WildCmp(wildcard, filename)
  1484.     msg     =    WaitMsg(msg)
  1485.     msg/NULL=    CheckMsg(msg)
  1486.     msg/NULL=    CheckPort(port)
  1487.     (void)  =   LockAddr(&varlock)      (long varlock[2] = { 0,0 })
  1488.     (void)  =   LockAddrB(bitno, &varlock)
  1489.     (void)  =   UnLockAddr(&varlock)
  1490.     (void)  =   UnLockAddrB(bitno, &varlock)
  1491.     (void)  =   DoSyncMsg(port, msg)    (do not setup reply port for message)
  1492.     node/NULL=    FindName2(list, name)   (ignores NULL ln_Name fields)
  1493.     ptr     =    GetTaskData(name, bytes)
  1494.     (void)  =   FreeTaskData(name)
  1495.  
  1496.                 LISTS
  1497.  
  1498.     node    =    GetHead(list)
  1499.     node    =    GetTail(list)
  1500.  
  1501.     node    =    GetSucc(list/node)
  1502.     node    =    GetPred(node)
  1503.  
  1504.     sptr    =    GetHeadOff(list, offset)
  1505.     sptr    =    GetTailOff(list, offset)
  1506.     sptr    =    GetSuccOff(sptr, offset)
  1507.     sptr    =    GetPredOff(sptr, offset)
  1508.  
  1509.     (void)  =   EnqueueLong(list, start, node, valoff)
  1510.     (void)  =   EnqueueOffLong(list, start, sptr, off, valoff)
  1511.  
  1512.     rval    =    SearchFwdNode(node, function, arg)
  1513.     rval    =    SearchRvsNode(node, function, arg)
  1514.     rval    =    SearchFwdList(list, function, arg)
  1515.     rval    =    SearchRvsList(list, function, arg)
  1516.     rval    =    SearchFwdNodeOff(sptr, function, off, arg)
  1517.     rval    =    SearchRvsNodeOff(sptr, function, off, arg)
  1518.     rval    =    SearchFwdListOff(list, function, off, arg)
  1519.     rval    =    SearchRvsListOff(list, function, off, arg)
  1520.  
  1521.         >>    function(sptr:4(sp)orA2, arg:8(sp)orD4)
  1522.  
  1523.                   MEMORY
  1524.  
  1525.     (void)  =   BZero(buf, bytes)
  1526.     (void)  =   BSet(buf, bytes, char)
  1527.     (void)  =   BMov(src, dest, bytes)
  1528.     BOOL    =    BCmp(src, dest, bytes)      0=failed, 1=success
  1529.  
  1530.                   TIMEDATE
  1531.  
  1532.     DOSBOOL =    SetFileDate(file, date)     0=failed, -1=success
  1533.     char *  =    DateToS(datestamp, buf, format)
  1534.  
  1535.                   RESOURCES (NOT IMPLEMENTED YET)
  1536.  
  1537. \Rogue\Monster\
  1538. else
  1539.   echo "will not over write runlib.doc"
  1540. fi
  1541. if [ `wc -c runlib.doc | awk '{printf $1}'` -ne 2799 ]
  1542. then
  1543. echo `wc -c runlib.doc | awk '{print "Got " $1 ", Expected " 2799}'`
  1544. fi
  1545. if `test ! -s timedate.doc`
  1546. then
  1547. echo "writing timedate.doc"
  1548. cat > timedate.doc << '\Rogue\Monster\'
  1549.  
  1550.  
  1551.                    TIMEDATE.DOC
  1552.  
  1553.     Useful routines...
  1554.  
  1555. SetFileDate                            SetFileDate
  1556.  
  1557.     DOSBOOL =  SetFileDate(file, date)
  1558.     char *file;
  1559.     DATESTAMP *date;
  1560.  
  1561.     This routine sets the datestamp for a file by implementing the new
  1562.     ACTION_SETDATE Dos packet.    0 is returned on failure, non-zero (-1)
  1563.     on success.
  1564.  
  1565.     NOTE:   The routine will fail if the file has been locked, shared or
  1566.     otherwise.
  1567.  
  1568.  
  1569. DateToS                             DateToS
  1570.  
  1571.     buf = DateToS(date, buf, format)
  1572.  
  1573.     DATESTAMP *date;
  1574.     char *buf;
  1575.     char *format;
  1576.  
  1577.     This routine calculates the ascii time and date from the datestamp and
  1578.     jams it into the output buffer (which is returned) according to the
  1579.     specified format string.  If the format string is NULL, "D M Y h:m:s"
  1580.     is used.  Essentially, the characters D,M,Y,h,m, and s are replaced by
  1581.     their ascii date equivalents (day, month, year, hours, minutes, seconds)
  1582.     in the output buffer, with all other characters copied verbatim.
  1583.  
  1584.  
  1585. \Rogue\Monster\
  1586. else
  1587.   echo "will not over write timedate.doc"
  1588. fi
  1589. if [ `wc -c timedate.doc | awk '{printf $1}'` -ne 968 ]
  1590. then
  1591. echo `wc -c timedate.doc | awk '{print "Got " $1 ", Expected " 968}'`
  1592. fi
  1593. echo "Finished archive 1 of 1"
  1594. # if you want to concatenate archives, remove anything after this line
  1595. exit
  1596. -- 
  1597. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  1598. Have five nice days.
  1599.